package com.swak.job;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

import com.swak.annotation.Context;
import com.swak.loadbalance.LoadBalances;
import com.swak.utils.StringUtils;
import com.swak.utils.time.DateTimes;

import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;

/**
 * 定时任务： 仅仅是数据库中的一条记录
 * 
 * @author lifeng
 */
@Getter
@Setter
@Accessors(chain = true)
public class Job {
	private String id; // 调度任务ID
	private String name; // 调度任务名称
	private String cronExpression; // 调度时间
	private Boolean order; // 按顺序调度，第一次调度执行完成时候，才能继续调度。保证所有的执行者执行完成（不保证一定执行成功）
	private Boolean autorun; // 任务是否自动运行; 非自动运行的任务可以通过管理后台调度运行
	private Long lastDispatchId;// 最后的调度号
	private String dispatchArguments; // 运行时动态参数
	private LocalDateTime lastDispatchTime; // 最后调度时间
	private LocalDateTime nextDispatchTime; // 最后调度时间

	// 当前配置信息
	private LoadBalances dispatchLoadBalance = LoadBalances.WeightingRoundRobin;
	private int parallel;
	private Object jobService;
	private Method dispatchMethod;
	private Method executeMethod;
	private int dispatchTasks;
	private String group;
	private int weight;
	private int retryTimes;
	// private boolean retryJob;
	private boolean isolate;
	private boolean opened;
	private boolean runOnBoot;

	public JobDispatch newDispatch() {
		JobDispatch dispatch = new JobDispatch();
		dispatch.setJobId(id);
		dispatch.setJobName(name);
		dispatch.setCreateTime(DateTimes.now());
		return dispatch;
	}

	static Job create(JobConfig config, com.swak.annotation.Job job, Object jobService, Method dispatchMethod,
			Method executeMethod) {

		/*
		 * 确定任务唯一标识
		 */
		String id = StringUtils.isBlank(job.id()) ? jobService.getClass().getSimpleName() : job.id();

		/*
		 * 重试：一个模块只需要设置一组重试, 这里指定一个固定的名称
		 */
//		if (job.retryJob()) {
//			id = "RetryJob";
//		}

		/*
		 * 确定任务并行度
		 */
		int parallel = job.parallel();
		if (job.context() == Context.Concurrent) {
			parallel = parallel <= 0 ? config.getWorkerPoolSize() / 2 : parallel;
		} else if (job.context() == Context.Order) {
			parallel = parallel <= 0 ? 1 : parallel;
		} else {
			parallel = 1;
		}
		if ((job.context() == Context.Concurrent || job.context() == Context.Order)
				&& StringUtils.isNotBlank(job.pool())) {
			parallel = parallel <= 0 ? job.workers() / 2 : parallel;
		}

		return new Job().setId(id).setName(job.name()).setParallel(parallel).setCronExpression(job.cronExpression())
				.setOrder(job.order()).setAutorun(job.autorun()).setJobService(jobService)
				.setDispatchMethod(dispatchMethod).setExecuteMethod(executeMethod).setDispatchTasks(job.dispatchTasks())
				.setGroup(job.group()).setDispatchLoadBalance(job.loadBalance()).setWeight(job.weight())
				// .setRetryJob(job.retryJob())
				.setRetryTimes(job.retryTimes()).setIsolate(job.isolateExecute()).setOpened(job.opened())
				.setRunOnBoot(job.runOnBoot());
	}
}